﻿#ifndef TFTP_H
#define TFTP_H

#include <stdint.h>
#include <QString>
#include <QtNetwork>

namespace TFTP {

//! 操作码列表
enum OPcodes : quint16{
    OInvalid,	///< 操作码无效
    RRQ,		///< 读取请求
    WRQ,		///< 写入请求
    DATA,		///< 数据包
    ACK,		///< 确认包
    ERROR		///< 错误
};

//!  错误码
enum ErrorCode {
    Undefined,      ///< 未知错误.
    FileNotFound,	///< File not found.
    AccessViolation,///< Access violation.
    DiskFull,       ///< Disk full or allocation exceeded.
    IllegalOp,      ///< 非法操作.
    UnknownTID,     ///< 未知 ID.
    FileExists,     ///< File already exists.
    NoUser          ///< No such user.
};

//! 传输模式
enum TransferMode {
    MInvalid,	///< 无效模式
    NetAscii,	///< ASCII-mode transfer
    Octet,		///< Binary-mode transfer
    Mail		///< Mail transfer (not supported)
};

/**
* @struct   TransferInfo
* @brief 传输参数,此结构包含传输会话所需的所有字段
*   找到自己并将数据发送到正确的对等方
*/
class TransferInfo {
public:
    QUdpSocket         *    sd;		///<
    const QHostAddress      dAddr;	///< 传输对方的地址
    const quint16           dPort;	///< 传输对方的端口

public:
    TransferInfo() :
        sd(nullptr)
      , dAddr(QHostAddress())
      , dPort(0)
    { }

    /**
    * @brief 构造函数
    * @param 指向要使用和获取信息的sd指针
    */
    TransferInfo(QUdpSocket *d) :
        sd(d)
      , dAddr(sd->peerAddress())
      , dPort( sd->peerPort())
    { }

    /**
        * @brief 参数化构造函数
        * @param d 指向要使用的Socket指针
        * @param a 传输对方的地址
        * @param p 传输对方的端口
        */
    TransferInfo(QUdpSocket *d
                 , const QHostAddress &a
                 , const quint16  p) :
        sd(d)
      , dAddr(a)
      , dPort(p)
    { }
public:
    /**
    * @brief 比较两个TransferInfo对象之间的运算符
    * @param b 要比较的第一个实例
    * @return 返回结果
    * - true 如果所有字段都相等
    */
   inline bool operator ==(const TransferInfo &b)
    {
        return	this->sd == b.sd &&
                this->dAddr == b.dAddr &&
                this->dPort == b.dPort;
    }

   /**
   * @brief 发送错误提示
   * @param ec 错误码
   * @param errMsg  错误码
   数据包格式如下:
   <pre>
       2 bytes  2 bytes        string    1 byte
       ----------------------------------------
       ERROR | 05|  ErrorCode |ErrMsg   |   0  |
       ----------------------------------------
   </pre>
   */
   void sendError(ErrorCode ec, const QString &errMsg);
};

};

#endif
